package ar.edu.itba.it.cg.grupo01.impl;

import java.awt.Color;

import ar.edu.itba.it.cg.grupo01.api.Intersection;
import ar.edu.itba.it.cg.grupo01.api.color.ColorMode;
import ar.edu.itba.it.cg.grupo01.api.color.ColorVariation;
import ar.edu.itba.it.cg.grupo01.api.image.Image;
import ar.edu.itba.it.cg.grupo01.api.scene.Scene;
import ar.edu.itba.it.cg.grupo01.api.shape.Shape;
import ar.edu.itba.it.cg.grupo01.impl.image.ImageImpl;
import ar.edu.itba.it.cg.grupo01.impl.scene.SceneFactory;

public class RayCaster {

	private CameraFactory cameraFactory;
	private SceneFactory sceneFactory;

	public RayCaster(CameraFactory cameraFactory, SceneFactory sceneFactory) {
		this.cameraFactory = cameraFactory;
		this.sceneFactory = sceneFactory;
	}

	public Image drawImage(RayCasterOptions options, int typeIntRgb) {

		Camera camera = cameraFactory.getDefaultCamera(options.getWidth(),
				options.getHeight(), options.getFov());
		Scene scene = sceneFactory.forName(options.getSceneName());
		Image image = new ImageImpl(options.getWidth(), options.getHeight(),
				typeIntRgb);
		ColorMode colorMode = options.getColorMode();
		ColorVariation colorVariation = options.getColorVariation();

		for (CameraRay ray : camera) {

			// Background color
			Color color = Color.BLACK;

			double currentDistance = Double.MAX_VALUE;
			for (Shape shape : scene) {

				Intersection<? extends Shape> intersection = shape
						.intersects(ray);

				if (intersection.intersects()) {
					double distance = intersection.distance(camera.getOrigin());
					if (distance < currentDistance) {
						// Initialize shape color
						if (shape.getColor() == null) {
							Color modeColor = colorMode.getColor();
							shape.setColor(modeColor);
						}
						color = colorVariation.apply(camera, shape,
								intersection);
						currentDistance = distance;
					}
				}

			}

			image.setPixel(ray.getX(), ray.getY(), color);
		}

		return image;

	}

	public static class RayCasterOptions {

		private final String sceneName;
		private int width = 640;
		private int height = 480;
		private double fov = 60.0;

		private ColorMode colorMode;
		private ColorVariation colorVariation;
		private String outputFile = null;
		private boolean showTime = false;

		public RayCasterOptions(final String sceneName, ColorMode defaultMode, ColorVariation defaultVariation) {
			this.sceneName = sceneName;
			this.colorMode = defaultMode;
			this.colorVariation = defaultVariation;
			
			// Output defaults to sceneName.png
			String[] splitName = sceneName.split("\\.");
			this.outputFile = splitName[0] + ".png";
		}

		public String getSceneName() {
			return sceneName;
		}

		public int getWidth() {
			return width;
		}

		public int getHeight() {
			return height;
		}

		public double getFov() {
			return fov;
		}

		public ColorMode getColorMode() {
			return colorMode;
		}

		public ColorVariation getColorVariation() {
			return colorVariation;
		}

		public String getOutputFile() {
			return outputFile;
		}

		public boolean isShowTime() {
			return showTime;
		}

		public void setWidth(int width) {
			this.width = width;
		}

		public void setHeight(int height) {
			this.height = height;
		}

		public void setFov(double fov) {
			this.fov = fov;
		}

		public void setColorMode(ColorMode colorMode) {
			this.colorMode = colorMode;
		}

		public void setColorVariation(ColorVariation colorVariation) {
			this.colorVariation = colorVariation;
		}

		public void setOutputFile(String outputFile) {
			this.outputFile = outputFile;
		}

		public void setShowTime(boolean showTime) {
			this.showTime = showTime;
		}

	}

}
